package cn.ztydata.teachingsystem.heaven.service;

import cn.ztydata.teachingsystem.common.Page;
import cn.ztydata.teachingsystem.exception.ServiceException;
import cn.ztydata.teachingsystem.heaven.common.WebContext;
import cn.ztydata.teachingsystem.heaven.dao.ChapterDao;
import cn.ztydata.teachingsystem.heaven.dao.ChapterOverviewDao;
import cn.ztydata.teachingsystem.heaven.dao.ResourceDao;
import cn.ztydata.teachingsystem.heaven.dao.redis.ChapterKpDao;
import cn.ztydata.teachingsystem.heaven.dao.redis.ChapterRelationDao;
import cn.ztydata.teachingsystem.heaven.dao.redis.ChapterRscDao;
import cn.ztydata.teachingsystem.heaven.entity.Chapter;
import cn.ztydata.teachingsystem.heaven.entity.Resource;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.MessageFormat;
import java.util.List;
import java.util.Map;

/**
 * 章节服务类
 * Created by chenxin on 2014/12/16.
 */
@Service
public class ChapterService extends BaseService {
    @Autowired
    private ChapterDao chapterDao;
    @Autowired
    private ChapterRscDao chapterRscDao;
    @Autowired
    private ChapterRelationDao chapterRelationDao;
    @Autowired
    private ChapterOverviewDao chapterOverviewDao;
    @Autowired
    private ChapterKpDao chapterKpDao;
    @Autowired
    private ResourceDao resourceDao;

    @Autowired
    private TeacherTeamService teacherTeamService;
    @Autowired
    private KpService kpService;

    @Autowired
    private WebContext webContext;

    /**
     * 获取节点模块信息
     * @param nodeId 节点ID
     * @return Chapter
     *
     * @author cx
     * @since 2014-12-16
     */
    public Chapter getModuleInfo(final long nodeId) {
        Chapter chapter = chapterDao.getForModule(nodeId);

        if (chapter == null) {
            log.debug("未获取到不存在的节点信息:chapter == null");
            throw new ServiceException("未获取到不存在的节点信息");
        }
        log.debug("返回获取到的节点模块儿信息");
        return chapter;
    }

    /**
     * 更新模块信息
     * @param chapter 章节实体类
     *
     * @author cx
     * @since 214-12-16
     */
    public void updateModuleInfo(Chapter chapter) {
        //判断节点是否可操作
        checkNode(chapter.getId());

        if (!chapterDao.updateForModule(chapter)) {
            log.debug("更新模块信息失败:!chapterDao.updateForModule(chapter)");
            log.warn("更新模块信息失败:nodeId->" + chapter.getId());
            throw new ServiceException();
        }
    }

    /**
     * 保存章节与资源的关系
     *
     * @author chenxin
     * @since 2014/12/17
     */
    public void saveRsc(final long nodeId, final long rscId) {
        //判断节点是否可操作
        checkNode(nodeId);

        //判断章节中是否已存在资源
        List<Long> rscIds = chapterRscDao.getAll(nodeId);
        if (rscIds.contains(rscId)) {
            log.debug("判断资源是否重复绑定:rscIds.contains(rscId)");
            log.warn("资源重复绑定:nodeId->" + nodeId + ",rscId->" + rscId);
            throw new ServiceException("该资源已经被选用");
        }

        //保存章节与资源的关系
        Boolean result = chapterRscDao.saveRsc(nodeId, rscId);
        if (result == null || !result) {
            log.debug("保存章节与资源的关系失败:result == null || !result");
            log.warn("保存章节与资源的关系失败:result->" + result);
            throw new ServiceException();
        }
    }

    /**
     * 删除章节与资源的关系
     *
     * @author chenxin
     * @since 2014/12/17
     */
    public void deleteRsc(final long nodeId, final long rscId) {
        //判断节点是否可操作
        checkNode(nodeId);

        //删除章节与资源的关系
        Boolean result = chapterRscDao.delete(nodeId, rscId);
        if (result == null || !result) {
            log.debug("删除章节与资源的关系结果:result == null || !result");
            log.warn("删除失败:nodeId->" + nodeId + ",rscId->" + rscId);
            throw new ServiceException();
        }
    }

    /**
     * 获取章节的资源列表
     *
     * @author chenxin
     * @since 2014/12/17
     */
    public Page<Resource> getRscList(final int pageNum, final int pageSize, final long nodeId) {
        //获取章节的资源总数
        int total = chapterRscDao.getLength(nodeId).intValue();

        if (total == 0) {
            log.debug("获取章节的资源总数为空：total == 0");
            return new Page<>();
        }

        //分页获取资源的ID
        List<Long> rscIds = chapterRscDao.getList(pageNum, pageSize, nodeId);
        //获取资源信息
        List<Resource> rscList = resourceDao.getList(rscIds);

        Map<Long, Resource> rscMap = Maps.newHashMap();
        log.debug("获取知识点+转存map");
        for (Resource res : rscList) {
            //获取资源的知识点
            res.setKps(kpService.getKpsForRes(res.getId()));

            //资源对象存入map，用于后面的排序
            rscMap.put(res.getId(), res);
        }

        //按照资源的绑定顺序输出
        List<Resource> result = Lists.newArrayList();
        log.debug("按照资源原有顺序输出:for (Long rscId : rscIds)");
        for (Long rscId : rscIds) {
            //资源在经过范围查询后，可能有些查询条件不满足，导致结果小于指定的范围
            if (null != rscMap.get(rscId)) {
                result.add(rscMap.get(rscId));
            }
        }

        rscMap = null;
        rscList = null;
        rscIds = null;
        log.debug("获取章节的资源列表");
        return new Page<>(total, pageSize, pageNum, result);
    }

    /**
     * 更新节点名称
     *
     * @author chenxin
     * @since 2014/12/19
     */
    public void updateChapter(Chapter chapter) {
        //检查节点是否可操作
        checkNode(chapter.getId());

        if (!chapterDao.updateName(chapter)) {
            log.debug("更新节点名称失败:!chapterDao.updateName(chapter)");
            log.warn("更新节点名称失败:nodeId->" + chapter.getId());
            throw new ServiceException();
        }
    }

    /**
     * 保存节点
     *
     * @author chenxin
     * @since 2014/12/19
     */
    @Transactional
    public void saveChapter(Chapter chapter) {
        //判断用户是否在课程的教师团队
        teacherTeamService.isMemeber(chapter.getCourseId());

        //新增节点记录
        if (!chapterDao.save(chapter)) {
            log.debug("新增节点失败:!chapterDao.save(chapter)");
            log.warn("新增节点失败");
            throw new ServiceException();
        }

        //新增概况记录
        if (!chapterOverviewDao.save(chapter.getId())) {
            log.debug("新增概况记录失败:!chapterOverviewDao.save(chapter.getId())");
            log.warn("新增概况记录失败");
            throw new ServiceException();
        }

        //保存父子节点关系
        chapterRelationDao.saveSonNode(chapter.getParentId(), chapter.getId());
    }

    /**
     * 删除章节节点
     *
     * @author chenxin
     * @since 2014/12/19
     */
    @Transactional
    public void deleteChapter(final long nodeId) {
        //判断节点是否可操作
        checkNode(nodeId);

        //判断节点是否存在子节点
        if (!chapterRelationDao.isEmpty(nodeId)) {
            log.debug("删除节点下存在子节点:!chapterRelationDao.isEmpty(nodeId)");
            log.warn("删除节点下存在子节点:nodeId->" + nodeId);
            throw new ServiceException("删除节点下存在子节点");
        }

        //获取删除节点的父节点
        Long parentId = chapterDao.getParentId(nodeId);
        if (parentId == null || parentId == 0) {
            log.debug("获取删除节点的父节点为空：parentId == null || parentId == 0");
            log.warn("删除节点失败:nodeId->" + nodeId + ",parentId->" + parentId);
            throw new ServiceException();
        }

        //删除节点记录
        if (!chapterDao.deleteById(nodeId)) {
            log.debug("删除节点记录失败:!chapterDao.deleteById(nodeId)");
            log.warn("删除节点记录失败:nodeId->" + nodeId);
            throw new ServiceException();
        }

        //删除节点的概况记录
        if (!chapterOverviewDao.deleteById(nodeId)) {
            log.debug("删除节点概况记录失败:!chapterOverviewDao.deleteById(nodeId)");
            log.warn("删除节点概况记录失败:nodeId->" + nodeId);
            throw new ServiceException();
        }

        //删除父子节点关系
        Boolean result = chapterRelationDao.deleteSonNode(parentId, nodeId);
        if (result == null || !result) {
            log.debug("删除父子关系失败:result == null || !result");
            log.warn("删除父子关系失败:nodeId->" + nodeId + ",parentId:" + parentId);
            throw new ServiceException();
        }

        //删除节点与关键字的关系
        chapterKpDao.deleteAll(nodeId);
        //删除节点与资源的关系
        chapterRscDao.deleteAll(nodeId);
    }

    /**
     * 更新拖拽节点的位置
     *
     * @author chenxin
     * @since 2014/12/22
     */
    public void updatePosition(final long draggedId, final long dependedId, final int type) {
        //判断节点是否可操作
        checkNode(draggedId);
        checkNode(dependedId);

        //拖动节点到目标节点内 -> 顺序插入
        if (type == 0) {
            log.debug("如果参数type不等于零：type == 0");
            //获取被拖拽节点的父节点编号
            Long parentId = chapterDao.getParentId(draggedId);

            //如果拖动节点不存在或为根节点，或者目标节点就是父节点
            if (parentId == null || parentId == 0 || parentId == dependedId) {
                log.debug("无效的节点拖动:parentId == null || parentId == 0 || parentId == dependedId");
                log.warn("无效的节点拖动:draggedId->" + draggedId + ",parentId=" + parentId + ",dependedId->" + dependedId);
                throw new ServiceException();
            }

            Boolean result = chapterRelationDao.updateSonNode(draggedId, parentId, dependedId);
            if (result == null || !result) {
                log.debug("更新子节点失败：result == null || !result");
                throw new ServiceException();
            }

            //更新拖拽节点的父节点
            if (!chapterDao.updateParentId(draggedId, dependedId)) {
                log.debug("更新拖拽节点的父节点失败:!chapterDao.updateParentId(draggedId, dependedId)");
                log.warn("更新拖拽节点的父节点失败:draggedId->" + draggedId + ",dependedId->" + dependedId);
                throw new ServiceException();
            }

            return;
        }

        //拖动节点到目标节点前后
        if (type == 1 || type == 2) {
            log.debug("type == 1 || type == 2");
            //获取拖拽节点的父节点编号
            Long draggedPid = chapterDao.getParentId(draggedId);
            //获取参照节点的父节点编号
            Long dependedPid = chapterDao.getParentId(dependedId);

            //如果拖动节点或目标节点不存在或为根节点
            if (draggedPid == null || draggedPid == 0 || dependedPid == null || dependedPid == 0) {
                log.debug("无效的节点拖动:draggedPid == null || draggedPid == 0 || dependedPid == null || dependedPid == 0");
                log.warn("无效的节点拖动:draggedId->" + dependedId + ",dependedId" + dependedId);
                throw new ServiceException();
            }

            Boolean result = chapterRelationDao.updateSonNode(draggedId, draggedPid, dependedId, dependedPid, type);
            if (result == null || !result) {
                log.debug("更新子节点1:result == null || !result");
                throw new ServiceException();
            }

            //更新拖拽节点的父节点
            if (draggedPid != dependedPid) {
                log.debug("更新拖拽节点的父节点:draggedPid != dependedPid");
                if (!chapterDao.updateParentId(draggedId, dependedPid)) {
                    log.debug("更新拖拽节点的父节点失败1:!chapterDao.updateParentId(draggedId, dependedPid)");
                    log.warn("更新拖拽节点的父节点失败:draggedId->" + draggedId + ",dependedPid->" + dependedPid);
                    throw new ServiceException();
                }
            }

            return;
        }

        log.debug("无效的拖拽方式");
        log.warn("无效的拖拽方式:type->" + type);
        throw new ServiceException();
    }

    /**
     * 获取子节点集合
     *
     * @author chenxin
     * @since 2014/12/22
     */
    public List<Chapter> getList(final long nodeId, final long courseId) {
        if (nodeId == 0) {
            log.debug("如果节点ID为零：nodeId == 0");
            //单取课程根节点
            Chapter root = chapterDao.getRootNode(courseId);
            if (root == null) {
                log.debug("单取课程根节点失败：root == null");
                return Lists.newArrayList();
            }

            log.debug("单取课程根节点失败成功");
            return Lists.newArrayList(root);
        }

        //获取指定节点的子节点集合
        List<Long> sonIds = chapterRelationDao.getSonNodes(nodeId);
        //获取子节点的信息
        List<Chapter> sonNodes = chapterDao.getAll(sonIds);

        //转换为"章节ID->章节信息"的格式
        Map<Long, Chapter> map = Maps.newHashMap();
        log.debug("转换为章节ID->章节信息的格式:for (Chapter chapter : sonNodes)");
        for (Chapter chapter : sonNodes) {
            map.put(chapter.getId(), chapter);
        }

        List<Chapter> result = Lists.newArrayList();
        log.debug("将指定节点的子节点集合放入result：for (Long sonId : sonIds)");
        for (Long sonId : sonIds) {
            result.add(map.get(sonId));
        }

        map = null;
        sonNodes = null;
        log.debug("获取子节点集合");
        return result;
    }

    /**
     * 判断节点包含子节点
     *
     * @author chenxin
     * @since 2014/12/22
     */
    public boolean isParent(final long nodeId) {
        log.debug("判断节点包含子节点");
        return chapterRelationDao.isEmpty(nodeId) ? false : true;
    }

    /**
     * 更新资源顺序
     *
     * @author chenxin
     * @since 2014/12/30
     */
    public void updateRscPosition(final long nodeId, final long draggedId, final long dependedId, final int type) {
        //判断节点是否可操作
        checkNode(nodeId);

        if (!chapterRscDao.updateRscPosition(nodeId, draggedId, dependedId, type)) {
            log.debug("拖拽章节资源顺序失败:!chapterRscDao.updateRscPosition(nodeId, draggedId, dependedId, type)");
            log.warn(MessageFormat.format("拖拽章节资源顺序失败:nodeId->{0},draggedId->{1},dependedId->{2},type->[3]",
                    nodeId, draggedId, dependedId, type));

            throw new ServiceException();
        }
    }

    /**
     * 检查节点是否可操作
     *
     * @author chenxin
     * @since 2014/12/30
     */
    public void checkNode(final long nodeId) {
        //获取节点所属课程ID
        Long courseId = chapterDao.getCourseId(nodeId);
        if (courseId == null) {
            log.debug("无效的节点ID:courseId == null");
            log.warn("无效的节点ID:courseId->null");
            throw new ServiceException();
        }

        //判断用户是否在课程的教师团队
        teacherTeamService.isMemeber(courseId);
    }

    /**
     * 检查节点是否可操作
     *
     * @author chenxin
     * @since 2014/12/30
     */
    public void checkNode(final long nodeId, final long courseId) {
        //获取节点所属课程ID
        Long nodeCourseId = chapterDao.getCourseId(nodeId);
        if (nodeCourseId == null || nodeCourseId != courseId) {
            log.debug("无效的节点ID：nodeCourseId == null || nodeCourseId != courseId");
            log.warn("无效的节点ID:nodeCourseId->" + nodeCourseId + ",courseId->" + courseId);
            throw new ServiceException();
        }

        //判断用户是否在课程的教师团队
        teacherTeamService.isMemeber(nodeCourseId);
    }

    /**
     * 获取所有子节点
     * @param courseId 课程编号
     * @param parentId 父编号
     * @return List
     *
     * @author fanruiping
     * @since 2015-04-03
     */
    public List<Chapter> getSonsByParentId(Long courseId, Long parentId){
        Chapter rootNode = null;

        //判断是否是获取章
        if(courseId != 0 && parentId == 0){
            log.debug("课程编号不为0且父编号为0:courseId != 0 && parentId == 0");

            rootNode = chapterDao.getRootNode(courseId);

            if(rootNode == null){
                log.debug("未获取到课程跟章节信息:rootNode == null");

                throw new ServiceException("未获取到根节点");
            }

            return chapterDao.getByParentId(rootNode.getId());
        }else {
            log.debug("课程编号为0获取父编号不为0");

            return chapterDao.getByParentId(parentId);
        }
    }
}
